﻿using Microsoft.Data.SqlClient;
using MySqlConnector;
using Simple.Common.Authentication;
using Simple.Common.Extensions;
using Simple.Repository.Models.Conversation;
using Simple.Services.System.Dictionary.Models;

namespace Simple.Services.System.Conversation
{
    public class ConversationService : BusinessBaseService
    {
        private readonly SimpleDbContext _context;
        private readonly ICurrentUserService _currentUserService;
        private readonly ChildrenService _childrenService;
        private readonly FileInfo.FileInfoService _fileInfoService;

        public ConversationService(
            SimpleDbContext context,
            ISimpleService services,
            ICurrentUserService currentUserService,
            ChildrenService childrenService,
            FileInfo.FileInfoService fileInfoService) : base(services)
        {
            _context = context;
            _currentUserService = currentUserService;
            _childrenService = childrenService;
            _fileInfoService = fileInfoService;
        }

        public async Task<List<ConversationModel>> List()
        {
            var result = new List<ConversationModel>();
            // 家长端获取对应教师
            if (_currentUserService.IsParent)
            {
                var childId =  _currentUserService.FindClaimValue(SimpleClaimTypes.ChildId);
                if (!string.IsNullOrWhiteSpace(childId))
                {
                    var teacherIds = await _childrenService.GetClassTeacherByChildIdAsync(Guid.Parse(childId));
                    if (teacherIds != null && teacherIds.Any())
                    {
                        var teacherUsers = _context.Set<SysUser>().Where(s => teacherIds.Contains(s.Id)).ToList();
                        foreach (var teacherUser in teacherUsers)
                        {
                            var message = await GetLastMessage(Guid.Parse(childId), teacherUser.Id, _currentUserService.UserId.Value, Enum.Parse<EnumParentRelationship>(_currentUserService.FindClaimValue(SimpleClaimTypes.Relationship)));
                            result.Add(new ConversationModel
                            {
                                ConversationId =  message?.ConversationId,
                                TargetId = teacherUser.Id,
                                Name = teacherUser.Name + "老师",
                                Portrait = await _fileInfoService.GetUserPortrait(teacherUser.Id),
                                LastMessage = message,
                                IsNewMessage = message == null ? false : (message.IsNewMessage && message.Sender != _currentUserService.UserId),
                            });
                        }
                    }
                }

            }
            else
            {
                var query = from c in _context.Set<Repository.Models.Conversation.Conversation>()
                            join p in _context.Set<Parent>()
                                on c.ParentId equals p.Id
                            join c1 in _context.Set<Childrens>()
                                on c.ChildId equals c1.Id
                            where c.TeacherId == _currentUserService.UserId && c.IsHidden == false
                            select new ConversationModel
                            {
                                ConversationId = c.Id,
                                TargetId = c.ParentId,
                                Name = c1.Name + c.Relationship.GetEnumDescription(),
                                Portrait = p.ImgId.HasValue ? p.ImgId.ToString() : null,
                            };
                result = await query.ToListAsync();
                if (result.Any())
                {
                    foreach (var item in result)
                    {
                        item.LastMessage = await _context.Set<ConversationRecord>().Where(s => s.ConversationId == item.ConversationId).OrderByDescending(s => s.CreatedTime).Select(c=>
                         new ConversationRecordModel
                        {
                             Content = c.Content,
                             MessageTime = c.CreatedTime,
                             Sender = c.Sender,
                             IsNewMessage = !c.IsRead
                         }).FirstOrDefaultAsync();
                        item.IsNewMessage = item.LastMessage == null ? false : (item.LastMessage.IsNewMessage && item.LastMessage.Sender != _currentUserService.UserId);
                    }
                }
            }

            return result;
        }

        private async Task<ConversationRecordModel> GetLastMessage(Guid childId, Guid teacherId, Guid parentId, EnumParentRelationship relationship)
        {
            var query = from c in _context.Set<ConversationRecord>()
                        join sc in _context.Set <Repository.Models.Conversation.Conversation>()
                           on c.ConversationId equals sc.Id
                        where sc.ChildId == childId && sc.ParentId == parentId && sc.Relationship == relationship && sc.TeacherId == teacherId
                        select new ConversationRecordModel
                        { 
                            ConversationId = c.ConversationId,
                            Content = c.Content,
                            MessageTime = c.CreatedTime,
                            Sender = c.Sender,
                            IsNewMessage = !c.IsRead
                        };
            return await query.OrderByDescending(s=>s.MessageTime).FirstOrDefaultAsync();
        }

        public async Task<List<ConversationRecordModel>> GetMessageHistory(Guid? conversationId)
        {
            if (conversationId == null)
                return new List<ConversationRecordModel>();
            var query = from r in _context.Set<ConversationRecord>()
                        join c in _context.Set<Repository.Models.Conversation.Conversation>()
                          on r.ConversationId equals c.Id
                        join p in _context.Set<Parent>()
                            on c.ParentId equals p.Id
                        join c1 in _context.Set<Childrens>()
                            on c.ChildId equals c1.Id
                        join u in _context.Set<SysUser>()
                            on c.TeacherId equals u.Id
                        where r.ConversationId == conversationId
                        select new ConversationRecordModel
                        {
                            ConversationId = c.Id,
                            ParentName = c1.Name + c.Relationship.GetEnumDescription(),
                            ParentPortrait = p.ImgId.HasValue ? p.ImgId.ToString() : null,
                            TeacherName = u.Name + "老师",
                            Content = r.Content,
                            IsNewMessage = !r.IsRead,
                            MessageTime = r.CreatedTime,
                            Sender = r.Sender,
                        };

            var history = await query.ToListAsync();
            if (history != null && history.Any())
            {
                var portrait =  await _fileInfoService.GetUserPortrait(_currentUser.UserId.Value);
                foreach (var item in history)
                {
                    item.TeacherPortrait = portrait;
                    item.IsMySend = item.Sender == _currentUser.UserId;
                }
                MySqlParameter parameter1 = new MySqlParameter("@conversationId", conversationId);
                MySqlParameter parameter2 = new MySqlParameter("@sender", _currentUser.UserId);
                await _context.Database.ExecuteSqlRawAsync("UPDATE ConversationRecord SET IsRead=true WHERE ConversationId = @conversationId AND Sender <> @sender", parameter1, parameter2);
                 await _context.SaveChangesAsync();
            }

            return history;
        }

        public async Task<SendConversationOutPutModel> SendMessage(SendConversationModel model)
        {
            if (model == null || string.IsNullOrWhiteSpace(model.Content))
            {
                throw AppResultException.Status403Forbidden("发送消息不能为空");
            }
            var result = new SendConversationOutPutModel();
            if (!model.ConversationId.HasValue && _currentUserService.IsParent)
            {
                var childId = _currentUserService.FindClaimValue(SimpleClaimTypes.ChildId);
                var relationship = Enum.Parse<EnumParentRelationship>(_currentUserService.FindClaimValue(SimpleClaimTypes.Relationship));
                var conversation = await _context.Set<Repository.Models.Conversation.Conversation>().Where(s => s.ChildId == Guid.Parse(childId) && s.ParentId == _currentUserService.UserId && s.TeacherId == model.TargetId && s.Relationship == relationship).FirstOrDefaultAsync();
                if (conversation == null)
                {
                    var entity = await _context.AddAsync(new Repository.Models.Conversation.Conversation
                    {
                        ParentId = _currentUserService.UserId.Value,
                        TeacherId = model.TargetId,
                        ChildId = Guid.Parse(childId),
                        Relationship = relationship,
                    });
                    model.ConversationId = entity.Entity.Id;
                }
                else
                {
                    if (conversation.IsHidden)
                    {
                        conversation.IsHidden = false;
                        _context.Update(conversation);
                    }
                }
            }

            var recordEntity = await _context.AddAsync(new ConversationRecord
            {
                  Content = model.Content,
                  ConversationId = model.ConversationId.Value,
                  Sender = _currentUserService.UserId.Value,
                  IsRead = false,
            });
            await _context.SaveChangesAsync();

            result.ConversationId = model.ConversationId.Value;
            result.Messages = await GetMessageHistory(result.ConversationId);
            return result;
        }

        public async Task<bool> Delete(string? conversationId)
        {
            if (!string.IsNullOrWhiteSpace(conversationId))
            {
                Guid id = Guid.Parse(conversationId);
                var entity = await _context.Set<Repository.Models.Conversation.Conversation>().Where(s => s.Id == id).FirstOrDefaultAsync();
                if (entity != null)
                {
                    entity.IsHidden = true;
                    _context.Update(entity);
                    await _context.SaveChangesAsync();
                }
            }
            return true;
        }
    }
}
